import React, { PureComponent } from 'react'
import ReduxByAdd from './components/ReduxByAdd'
import ReduxBySub from './components/ReduxBySub'
import store from './store'
import MobxDemo from './components/MobxDemo'

import { Routes, Route, Link, Navigate } from 'react-router-dom'
import RouterOne from './components/RouterOne'
import RouterTwo from './components/RouterTwo'
import RouterNotFound from './components/RouterNotFound'
import RouterSecondOne from './components/RouterSecondOne'
import RouterSecondTwo from './components/RouterSecondTwo'
import RouterPassParamsFather from './components/RouterPassParamsFather'
import RouterPassParamsSon from './components/RouterPassParamsSon'
import RouterPassLocationSon from './components/RouterPassLocationSon'

export class App extends PureComponent {
  constructor() {
    super()

    this.state = {
      stateCounter: store.getState().counter
    }
  }

  componentDidMount() {
    // 订阅：
    store.subscribe(() => {
      const stateCounter = store.getState()
      this.setState({
        stateCounter
      })
    })
  }

  render() {
    const { stateCounter } = this.state

    return (
      <div>
        {/* Redux 三个核心概念：Store、action */}
        {/* 
          1、Store：

          2、action：
          Redux 要求我们通过 action 来更新数据：
            所有数据的变化，必须通过派发（dispatch）action来更新
            action 是一个普通的 JavaScript 对象，用来描述这次更新的 type 和 content
          强制使用 action 的好处是可以清晰的知道数据到底发生了什么变化，所有数据的变化都是可追踪、可预测的
          当然，目前我们的 action 是固定的对象
          真实应用中，我们会通过函数来定义，返回一个 action

          3、reducer：
          reducer 就是将 state 和 action 联系在一起的一个纯函数
          reducer 做的事情就是将传入的 state 和 action 结合起来生成一个新的 state
          action 有两参数：
            1、第一个是 store 中目前保持的 state
            2、第二个是本次更新的 action （dispatch 传入的 action）
          返回值：
            它的返回值会作为 store 之后的存储的 state
        */}
        <h4>Redux 的使用：</h4>
        <h4>当前计数：{stateCounter}</h4>
        <ReduxByAdd stateCounter={stateCounter} />
        <ReduxBySub stateCounter={stateCounter} />
        {/* mobx：详情见 MobxDemo 组件 */}
        <h4>mobx</h4>
        <MobxDemo />
        {/* router 路由 */}
        {/* 
          Router 中包含了对路径改变的监听，并且会将相应的路径传递给子组件
          BrowserRouter 使用 history 模式
          HashRouter 使用 hash 模式
          使用：
            在 总的 index.js 中引入 BrowserRouter 或者 HashRouter ，并且包裹住 <App />

          Routes：包裹所有的 Route，在其中匹配路由，如下，可以使用 Link 实现路由跳转
          <Routes>
            <Route path="路由路径" element={ 组件 } />
          </Routes>

          Navigate 导航（用于跳转，比如登录页，登录成功后跳转），案例如下行：
            {isLogin ? <button>点击登录</button> : <Navigate to="/one" />}
          同时，还可以用作重定向页面：
            <Routes>
              <Route path="/" element={<Navigate to="/one" />} />
            <Routes>

          二级路由：在一级路由里面写二级路由的配置，详情见如下：
          注意配置出口，即占位组件：<Outlet />
          
          手动路由跳转：
          当你想使用非 Link 的元素进行跳转路由时，需要使用 hooks 中的 useNavigate()
          请注意：不能在普通的类组件中使用 useNavigate() 推荐使用函数组件，也可以在类组件中升级为高阶组件（不推荐）
          使用：
            1、const navigate = useNavigate()
            2、navigateTo() {
                navigate('path路径')
              }
            3、<button onClick={() => navigateTo()}>点击跳转</button>
          
          路由传参1（通过动态路由传参）：
          使用：
            1、在需要接收参数的 Route 中配置动态路由
            2、在传递参数的组件中，使用 Link 或 useNavigate() 传参，例如：const navigate = useNavigate()  navigate(`路径/${id}`)
            3、在需要接收参数的组件中，使用 useParams() 接收参数
          
          路由传参2（通过url的查询字符串传参）：
          使用：
            1、正常配置 Route
            2、在传递参数的组件中，使用 Link 或 useNavigate() 传参，例如：<Link to="/路径?name=mafei&age=20" />
            3、在需要接收参数的组件中，使用 useLocation() 或者 useSearchParams() 加上 Object.formEntries() 方法获得参数对象（推荐）

          单独将路由放在一个文件的配置：
          操作：
            1、在src目录下新建 router 文件夹，新建一个 index.js
            2、把之前在组件中配置的全部删掉，并重新以对象形式写在该 index.js 中
            3、在原本的组件中，引入这个 index.js 文件，同时在原本写路由的地方加上一句： {useRoutes(routes)}
            在 index.js 中：
            const routes = [
              {
                path: '/',
                element: <Navigate to='/路径' />
              },
              {
                path: '路径',
                element: 组件
              },
              {
                path: '路径',
                element: 组件,
                children: [
                  {
                    path: '路径',
                    element: 组件
                  }
                ]
              }
            ]
            export default routes

            路由懒加载：
            在 index.js 中可以通过 const 名字 = React.lazy(() => import("组件路径")) 将 原本的 import 名字 from '组件路径' 替换
            这样在打包的时候就会实现单独打包，实现路由懒加载
            同时，
            还需要在总的 index.js 中，在 BrowserRouter 或者 HashRouter 包裹的下一层，
            加一个 <Suspense fallback={<h3>Loading</h3>}></Suspense>，里面包裹 <App />
            表示如果页面在异步的懒加载的时候，页面还没出来的时候先显示 Suspense 里的 fallback 的内容
         */}
        <h4>router 路由</h4>
        <div className="header">这是头部header</div>
        <div>
          <Link to="/one">RouterOne</Link>
          <span> </span>
          <Link to="/two">RouterTwo</Link>
          <span> </span>
          <Link to="/passParamsFather">路由传参父页面</Link>
        </div>
        <hr />
        <div className="main">
          {/* router 5 写法： */}
          <Routes>
            {/* 使用重定向后（页面默认是 RouterOne）： */}
            <Route
              path="/"
              element={<Navigate to="/one" />}
            />
            {/* 普通页面： */}
            <Route
              path="/one"
              element={<RouterOne />}
            >
              {/* 二级路由： */}
              {/* 二级路由重定向： */}
              <Route
                path="/one"
                element={<Navigate to="/one/secondOne" />}
              />
              <Route
                path="/one/secondOne"
                element={<RouterSecondOne />}
              />
              <Route
                path="/one/secondTwo"
                element={<RouterSecondTwo />}
              />
            </Route>
            <Route
              path="/two"
              element={<RouterTwo />}
            />

            {/* 路由传参： */}
            <Route
              path="/passParamsFather"
              element={<RouterPassParamsFather />}
            />
            <Route
              path="/passParamsSon/:id"
              element={<RouterPassParamsSon />}
            />
            <Route
              path="/passLocationSon"
              element={<RouterPassLocationSon />}
            />

            {/* 404 页面： */}
            <Route
              path="*"
              element={<RouterNotFound />}
            />
          </Routes>
        </div>
        <hr />
        <div className="footer">这是尾部footer</div>
      </div>
    )
  }
}

export default App
